// 简单工厂模式（链式继承）-以水果店为例
// 这里通过结构体之间的包含，表示继承关系，通过转换成void指针实现向上转型，强制转换为具体结构体指针实现向下转型
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/// @brief 顾客口味枚举
typedef enum
{
	/// @brief 甜
	SWEET,
	/// @brief 酸甜
	SWEET_ACID,
	/// @brief 酸
	ACID
} Flavor;

/// @brief 水果抽象类
typedef struct
{
	char name[16];
} Fruit;

/// @brief 西瓜类
typedef struct
{
	Fruit *parentInfo; // 继承父类
	int cooked;		   // 是否保熟
} Watermelon;

/// @brief 苹果类
typedef struct
{
	Fruit *parentInfo; // 继承父类
	int sweetness;	   // 甜度
} Apple;

/// @brief 橙子类
typedef struct
{
	Fruit *parentInfo; // 继承父类
	int acidity;	   // 酸度
} Orange;

/// @brief 水果工厂方法
/// @param flavor 口味枚举
/// @return void指针，实质上是根据口味生成的各种水果对象的指针，使用时强行转换回去即可（向下转型）
void *fruitFactoryGet(Flavor flavor)
{
	void *fruit;
	// 水果父类
	Fruit *parent = (Fruit *)malloc(sizeof(Fruit));
	switch (flavor)
	{
	case SWEET:
		// 若顾客喜欢甜的，则生产西瓜
		strcpy(parent->name, "西瓜");
		Watermelon *watermelon = (Watermelon *)malloc(sizeof(Watermelon));
		watermelon->cooked = 1;
		watermelon->parentInfo = parent;
		// 向上转型，下面也一样
		fruit = (void *)watermelon;
		break;
	case ACID:
		// 若顾客喜欢酸的，则生产橙子
		strcpy(parent->name, "橙子");
		Orange *orange = (Orange *)malloc(sizeof(Orange));
		orange->acidity = 12;
		orange->parentInfo = parent;
		fruit = (void *)orange;
		break;
	case SWEET_ACID:
		// 若顾客喜欢酸甜的，则生产苹果
		strcpy(parent->name, "苹果");
		Apple *apple = (Apple *)malloc(sizeof(Apple));
		apple->sweetness = 100;
		apple->parentInfo = parent;
		fruit = (void *)apple;
		break;
	default:
		printf("输入错误！\n");
		break;
	}
	return fruit;
}

int main()
{
	// 水果店买水果了！
	printf("有个人前来买瓜...\n");
	Watermelon *buyWatermelon = (Watermelon *)fruitFactoryGet(SWEET); // 向下转型
	printf("顾客买到了：%s，这瓜保熟吗？%s\n", buyWatermelon->parentInfo->name, buyWatermelon->cooked ? "保熟！" : "不保熟！");
	return 0;
}